# -*-coding:utf-8-*-
from itertools import islice
"""
Iterable: 可迭代对象,实现了__iter__(不一定要实现__next__)或者__getitem__.凡是可以for循环的,都是Iterable.
        (注：判断一个对象是不是可迭代对象，利用isinstance(obj, Iterable)并不总是可靠的,该方法只检测是否实现了__iter__,
        对于仅实现了__getitem__的对象，该方法就会失效)
Iterator: 迭代器,实现了__iter__、__next__的对象,属于Iterable.凡是可以next()的，都是Iterator.
generator: 生成器, 用生成器函数iter()或使用关键字yield或使用生成器表达式(...for...in...)生成的对象,属于Iterator和Iterable.
list、tuple、dict、set、str属于Iterable但不属于Iterator,但可以通过iter()生成Iterator.

注意点：
(1) Iterator一般只可以循环一次，第二遍就获取不到数据了。
(2) Iterable一般可以循环多次（因为Iterable一般会实现__iter__返回一个全新的Iterator）
    但generator只可以循环一次,如：生成器表达式x=(i for i in range(10)),只能循环遍历一次,第一遍list(x)有效，第二遍list(x)为空
"""

# 使用enumerate()在循环中获取偏移和元素，此函数返回的是一个生成器对象
a = ['x', 'y']
for index, item in enumerate(a):
    print(index, item)


# 生成器yeild.生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器
def get_str_ord(_str):
    for char in _str:
        yield char, ord(char)


for c, o in get_str_ord('ab'):
    print(c, o)

ords = get_str_ord('ab')
print(next(ords))
print(next(ords))

# 生成器表达式,形式为括号+解析表达式,能实现yeild一样的效果
itter = (i*2 for i in range(10))
print(list(itter))
# 模拟实现zip函数
def myzip(*args):
    minlen = min(len(arg) for arg in args)
    return (tuple(s[i] for s in args) for i in range(minlen))
print(list(myzip((1, 2), (3, 4, 5))))

# 迭代器iter.字符串,列表,字典和元组等对象是可迭代对象,不是迭代器,但可以通过iter获取迭代器
ll = [1, 2, 3, 4]
it = iter(ll)
print(next(it))


# 通过实现__next__和__iter__方法使对象支持迭代,通过StopIteration确定停止迭代的条件
class IterDemo(object):

    def __init__(self, _str):
        self._str = _str
        self._index = 0

    def __next__(self):
        if self._index >= len(self._str):
            raise StopIteration()
        o = ord(self._str[self._index])
        self._index += 1
        return o

    def __iter__(self):
        return self

itr = IterDemo('ab')
# 可以通过对象的__next__()或者内置next()进行手动迭代
print(itr.__next__())
print(next(itr))

# 通过迭代器实现任意长度的斐波那契数列
class Fib(object):
    def __init__(self):
        self._pre = 0
        self._next = 1

    def __next__(self):
        self._pre, self._next = self._next, self._next+self._pre
        return self._pre

    def __iter__(self):
        return self

fib_list = list(islice(Fib(), 0, 10))
print(fib_list)
